<?php
/**
 * @copyright: ©2024 永州 微聚商网络科技有限公司
 * @link: https://www.wEijuyunke.com
 */
namespace app\common\service;

use think\facade\Log;

class ApiV3Pay
{

    /**
     * 获取相关配置
     */
    public function __construct($appid, $mch_id, $pay_key, $serial_no,$pay_service_appid ='')
    {
        $this->appid = $appid;
        $this->mch_id = $mch_id;
        $this->pay_key = $pay_key;
        $this->serial_no = $serial_no;
        $this->pay_service_appid = $pay_service_appid;

    }

    /**
     * 用于生成请求报文的主体,最终返回json格式数据
     *
     * @param $description :商品描述            
     * @param $out_trade_no :商户订单号            
     * @param $total :订单总金额            
     * @param $openid :小程序微信用户身份唯一标识符            
     * @return false|string
     */
    public function requestBody($description, $out_trade_no, $total, $openid)
    {
        $data = array(
            'appid' => $this->appid,
            'mchid' => $this->mch_id,
            'description' => $description,
            'out_trade_no' => $out_trade_no,
            'notify_url' => 'http://001.chutest.xyz/v3Result.php',
            'amount' => [
                'total' => $total
            ],
            'payer' => [
                'openid' => $openid
            ]
        );
        return json_encode($data);
    }

    /**
     * 用于生成请求报文的主体,最终返回json格式数据
     *
     * @param $log_no :批次单号唯一            
     * @param $total :转账总金额            
     * @param $openid :小程序微信用户身份唯一标识符            
     * @return false|string
     */
    public function transferBody($log_no, $total, $openid)
    {

        $data = array(
            'appid' => $this->appid,
            'out_batch_no' => $log_no,
            'batch_name' => date('Ymd') . "提现", // 批次名称
            'batch_remark' => date('Ymd') . "提现", // 批次备注
            'total_amount' => intval( $total), // 转账总金额
            'total_num' => 1,

            'transfer_detail_list' => [
                array(
                    'out_detail_no' => date('Ymd') . rand(1000, 9999),
                    'transfer_amount' => intval( $total),
                    'transfer_remark' => date('Ymd') . "提现", // 转账备注
                    'openid' => $openid
                )
            ]
        );
        return json_encode($data);
    }


    public function partnerTransferBody($log_no, $total, $openid)
    {

        $data = array(
            'sub_appid' => $this->appid,
            'sub_mchid' => $this->mch_id,
            'authorization_type' => 'INFORMATION_AND_FUND_AUTHORIZATION_TYPE',
            'out_batch_no' => $log_no,
            'batch_name' => date('Ymd') . "提现", // 批次名称
            'batch_remark' => date('Ymd') . "提现", // 批次备注
            'total_amount' =>intval( $total), // 转账总金额
            'total_num' => 1,

            'transfer_detail_list' => [
                array(
                    'out_detail_no' => $log_no,
                    'transfer_amount' => intval( $total),
                    'transfer_remark' => date('Ymd') . "提现", // 转账备注
                    'openid' => $openid
                )
            ],
            'sp_appid' => $this->pay_service_appid,
            'transfer_scene' => 'ORDINARY_TRANSFER',
        );
        return json_encode($data);
    }

    /**
     * 用于生成请求报文的主体,最终返回json格式数据
     *
     * @param $log_no :批次单号唯一            
     * @param $total :转账总金额            
     * @param $openid :小程序微信用户身份唯一标识符            
     * @return false|string
     */
    public function transferSearchBody($batch_id)
    {
        $data = array(
            'batch_id' => $batch_id,
            'need_query_detail' => 'true'
        );
        return json_encode($data);
    }

    /**
     * 用于生成签名数据主体
     *
     * @param $method :请求方法            
     * @param $disposeUrl :此处的url是接口地址去除域名后的url            
     * @param $nonce_str :32位随机字符串            
     * @param $requestBody :请求报文的主体            
     * @return string
     */
    public function signBody($method, $disposeUrl, $time, $nonce_str, $requestBody)
    {
        $data = array(
            $method,
            $disposeUrl,
            $time,
            $nonce_str,
            $requestBody,
            ''
        );
        return join("\n", $data);
    }

    /**
     * 用于生成签名值
     *
     * @param $data :用于签名的数据            
     * @return string
     */
    public function getSignature($data)
    {
        $key = $this->pay_key;
        
        $private = file_get_contents($key);
        $key = openssl_pkey_get_private($private);
        openssl_sign($data, $signature, $key, 'sha256WithRSAEncryption');
        return base64_encode($signature);
    }

    /**
     *
     * @param $nonce_str :32位随机字符串,与上方的随机字符串保持一致            
     * @param $signature :上方生成的签名值            
     * @return string[]
     */
    public function getHeader($nonce_str, $signature)
    {
        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $this->mch_id, $nonce_str, time(), $this->serial_no, $signature);
        
        $data = [
            'Accept: application/json',
            'User-Agent: */*',
            'Content-Type: application/json; charset=utf-8',
            'Authorization: ' . $token
        ];
        return $data;
    }


    public function getHeaderNew($nonce_str, $signature,$pay_platform_serial_no)
    {
        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $this->mch_id, $nonce_str, time(), $this->serial_no, $signature);

        $data = [
            'Accept: application/json',
            'User-Agent: */*',
            'Content-Type: application/json; charset=utf-8',
            'Authorization: ' . $token,
            'Wechatpay-Serial' =>$pay_platform_serial_no,
        ];
        return $data;
    }
    /**
     * 使用curl完成对接口的请求
     *
     * @param $url :接口的url地址            
     * @param string $type
     *            :传输类型,若为POST需要提供$data与$header
     * @param string $data
     *            :当type = POST时需要提供,为请求主体数据
     * @param array $header
     *            :当type = POST时需要提供,为请求头
     * @return bool|string
     */
    public function curlRequest($url, $type = '', $data = '', $header = [])
{
    $action = curl_init();
    curl_setopt($action, CURLOPT_URL, $url);
    curl_setopt($action, CURLOPT_CONNECTTIMEOUT, 60);
    curl_setopt($action, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($action, CURLOPT_HEADER, 0);
    curl_setopt($action, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($action, CURLOPT_SSL_VERIFYHOST, 0);
    if ($type == 'POST') {
        curl_setopt($action, CURLOPT_POST, 1);
        curl_setopt($action, CURLOPT_POSTFIELDS, $data);
        curl_setopt($action, CURLOPT_HTTPHEADER, $header);
    }
    $result = curl_exec($action);
    curl_close($action);
    return $result;
}

    public function curlNewRequest($url, $header = [])
    {
        $action = curl_init();
        curl_setopt($action, CURLOPT_URL, $url);
        curl_setopt($action, CURLOPT_CONNECTTIMEOUT, 60);
        curl_setopt($action, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($action, CURLOPT_HEADER, 0);
        curl_setopt($action, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($action, CURLOPT_SSL_VERIFYHOST, 0);



            curl_setopt($action, CURLOPT_HTTPHEADER, $header);

        $result = curl_exec($action);
        curl_close($action);
        return $result;
    }

    /**
     * 构造对prepay_id再次签名的签名数据主体
     *
     * @param $time :时间戳            
     * @param $nonceStr :32位随机字符串            
     * @param $prepay_id :预支付参数            
     * @return string
     */
    public function paySignBody($time, $nonceStr, $prepay_id)
    {
        $data = array(
            $this->appid,
            $time,
            $nonceStr,
            "prepay_id=$prepay_id",
            ''
        );
        return join("\n", $data);
    }

    /**
     * 构造返回给小程序段的数据,json数据
     *
     * @param $nonce_str :32位随机字符串            
     * @param $prepay_id :预支付参数            
     * @param $paySign :签名值            
     * @param $time :时间戳            
     * @param $out_trade_no :商户订单号            
     * @return false|string
     */
    public function requestPayData($nonce_str, $prepay_id, $paySign, $time, $out_trade_no)
    {
        $data = array(
            'nonceStr' => $nonce_str,
            'package' => 'prepay_id=' . $prepay_id,
            'paySign' => $paySign,
            'timeStamp' => $time,
            'signType' => 'RSA',
            'out_trade_no' => $out_trade_no
        );
        return json_encode($data);
    }

    public function transfer($log_no, $total_amount, $openid)
    {
        $nonce_str = createNonceStr();
        $time = time();

        $requestBody = $this->transferBody($log_no, $total_amount, $openid); // 获取请求主体的json数据

        $disposeUrl = '/v3/transfer/batches'; // 处理过后的url地址 注:去掉前方的域名即可
        $signBody = $this->signBody('POST', $disposeUrl, $time, $nonce_str, $requestBody); // 获取参与签名的主体数据

        $signature = $this->getSignature($signBody); // 获取签名值
        $header = $this->getHeader($nonce_str, $signature); // 获取请求头
        $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches'; // 接口的url地址
        $res = $this->curlRequest($url, 'POST', $requestBody, $header); // 获取预支付参数
        $result = json_decode($res, true);

        Log::error("ApiV3Pay transfer:" . $res);

        return $result;
    }


    public function partnerTransfer($log_no, $total_amount, $openid)
    {
        $nonce_str = createNonceStr();
        $time = time();

        $requestBody = $this->partnerTransferBody($log_no, $total_amount, $openid); // 获取请求主体的json数据

        $disposeUrl = '/v3/partner-transfer/batches'; // 处理过后的url地址 注:去掉前方的域名即可
        $signBody = $this->signBody('POST', $disposeUrl, $time, $nonce_str, $requestBody); // 获取参与签名的主体数据

        $signature = $this->getSignature($signBody); // 获取签名值
        $header = $this->getHeader($nonce_str, $signature); // 获取请求头
        $url = 'https://api.mch.weixin.qq.com/v3/partner-transfer/batches'; // 接口的url地址
        $res = $this->curlRequest($url, 'POST', $requestBody, $header); // 获取预支付参数
        $result = json_decode($res, true);
        Log::error("ApiV3Pay transfer:" . $res);
        return $result;
    }

    public function transferNew($log_no, $total_amount, $openid,$transfer_scene_id,$pay_platform_serial_no)
    {
        $nonce_str = createNonceStr();
        $time = time();

        $requestBody = $this->transferBodyNew($log_no, $total_amount, $openid,$transfer_scene_id); // 获取请求主体的json数据

        $disposeUrl = '/v3/fund-app/mch-transfer/transfer-bills'; // 处理过后的url地址 注:去掉前方的域名即可
        $signBody = $this->signBody('POST', $disposeUrl, $time, $nonce_str, $requestBody); // 获取参与签名的主体数据

        $signature = $this->getSignature($signBody); // 获取签名值
        $header = $this->getHeaderNew($nonce_str, $signature,$pay_platform_serial_no); // 获取请求头
        $url = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills'; // 接口的url地址
        $res = $this->curlRequest($url, 'POST', $requestBody, $header); // 获取预支付参数
        $result = json_decode($res, true);

        Log::error("ApiV3Pay transfer:" . $res);

        return $result;
    }


    public function transferBodyNew($log_no, $total, $openid,$transfer_scene_id)
    {
        $request = Request();
        $domain = $request->host();
        $data = array(
            'appid' => $this->appid,
            'out_bill_no' => $log_no,
            'openid' => $openid,
            'transfer_amount' => intval( $total),
            'transfer_remark' => date('Ymd') . "提现",
            'transfer_scene_id' => $transfer_scene_id,
            'user_recv_perception'=> '现金奖励',
            'notify_url' => "https://" . $domain . "/mobile/callback/wxCallback",
            'transfer_scene_report_infos' =>[
               ['info_type' => '活动名称', 'info_content'=> '佣金提现'],
               ['info_type' => '奖励说明', 'info_content'=> '佣金提现']

            ]


        );

        return json_encode($data);
    }

    public function rejectSubmit($log_no)
    {
        $nonce_str = createNonceStr();
        $time = time();


        $disposeUrl = '/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/'.$log_no.'/cancel'; // 处理过后的url地址 注:去掉前方的域名即可
        $signBody = $this->signBody('POST', $disposeUrl, $time, $nonce_str, ''); // 获取参与签名的主体数据
        $signature = $this->getSignature($signBody); // 获取签名值
        $header = $this->getHeader($nonce_str, $signature); // 获取请求头
        $url = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/'.$log_no.'/cancel'; // 接口的url地址
        $res = $this->curlRequest($url,'POST',[], $header); //

        $result = json_decode($res, true);
        Log::error("ApiV3Pay transfer:" . $res);

        return $result;
    }
    public function rejectSubmitBody($log_no)
    {

        $data = array(
            'out_bill_no' => $log_no,
        );
        return json_encode($data);
    }

    public function transferSelelct($log_no)
    {
        $nonce_str = createNonceStr();
        $time = time();

        $requestBody = $this->rejectSubmitBody($log_no); // 获取请求主体的json数据
        $disposeUrl = '/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/'.$log_no; // 处理过后的url地址 注:去掉前方的域名即可
        $signBody = $this->signBody('GET', $disposeUrl, $time, $nonce_str,''); // 获取参与签名的主体数据

        $signature = $this->getSignature($signBody); // 获取签名值
        $header = $this->getHeader($nonce_str, $signature); // 获取请求头
        $url = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/'.$log_no; ; // 接口的url地址
        $res = $this->curlNewRequest($url,  $header); // 获取预支付参数

        $result = json_decode($res, true);

        Log::error("ApiV3Pay transfer:" . $res);

        return $result;
    }


}
